<?php

namespace falcon5\inc\Http\Controllers;

use falcon5\inc\Http\Request;
use falcon5\inc\Http\JsonResponse;
use falcon5\inc\Infrastructure\Services\Falcon5Service;
use hollisho\helpers\ArrayHelper;
use hollisho\helpers\InvalidArgumentException;

/**
 * Class BaseController
 * @package falcon5\inc\Http\Controllers
 * @desc
 */
abstract class BaseController
{
    /**
     * require auth annotation
     */
    const REQUIRE_AUTH = 'requireAuth';
    
    /**
     * handle request
     * @param Request $request
     * @return JsonResponse
     */
    public function handleRequest(Request $request): JsonResponse
    {
        try {
            $action = $request->getAction();
            if (empty($action) || !method_exists($this, $action)) {
                throw new \InvalidArgumentException('Invalid action');
            }
            
            // check if method need permission verify
            $reflection = new \ReflectionMethod($this, $action);
            $docComment = $reflection->getDocComment();
            
            // if method annotation contains @requireAuth, then verify permission
            if ($docComment && strpos($docComment, '@' . self::REQUIRE_AUTH) !== false) {
                // use regex to extract params list
                $params = [];
                $pattern = '/@' . self::REQUIRE_AUTH . '\(([^)]*)\)/';
                if (preg_match($pattern, $docComment, $matches) && !empty($matches[1])) {
                    // parse param string, support comma separated param list
                    $paramStr = trim($matches[1]);
                    $paramList = explode(',', $paramStr);
                    foreach ($paramList as $param) {
                        $param = trim($param);
                        if (!empty($param)) {
                            $params[] = $param;
                        }
                    }
                }
                
                $authResult = $this->verifyPermission($request, $params);
                if ($authResult !== true) {
                    return $authResult;
                }
            }

            $response = $this->$action($request);
            if (!($response instanceof JsonResponse)) {
                $response = JsonResponse::success($response);
            }
            return $response;
        } catch (\Exception $e) {
            falcon5_error_log('Caught exception: ' . $e->getMessage());
            // Set appropriate HTTP status based on exception type
            $httpStatus = 500;
            $code = $e->getCode() ?: 500;
            
            // For specific exceptions, we can set different HTTP status codes
            if ($e instanceof \InvalidArgumentException) {
                $httpStatus = 400;
            }
            
            return JsonResponse::error($code, $e->getMessage(), null, $httpStatus);
        }
    }
    
    /**
     * verify user permission
     * @param Request $request
     * @param array $params custom request params
     * @return bool|JsonResponse if verify success return true, otherwise return JsonResponse error
     */
    protected function verifyPermission(Request $request, array $params = [])
    {
        // get default params
        $token = $request->get('token');
        
        // if no token provided, return error
        if (empty($token)) {
            return JsonResponse::error(401, 'no permission', null, 401);
        }
        
        // build verify params
        $authParams = ['token' => $token];
        
        // add custom params to verify params
        foreach ($params as $param) {
            $value = $request->get($param);
            if ($value !== null) {
                $authParams[$param] = $value;
            }
        }
        
        // verify token is valid
        try {
            /** @var Falcon5Service $service */
            $service = falcon5_app(Falcon5Service::class);
            
            // use custom params to verify permission
            $result = $service->checkUserLanguageEditPermission($authParams);
            
            // assume result contains permission info
            $code = ArrayHelper::getValue($result, 'code', 0);
            
            if ($code !== 1) {
                $msg = ArrayHelper::getValue($result, 'msg', 'verify failed');
                $code = ArrayHelper::getValue($result, 'code', 0);
                return JsonResponse::error($code, $msg, null, $code);
            }
            
            return true;
        } catch (\Exception $e) {
            return JsonResponse::error(500, 'permission verify error: ' . $e->getMessage(), null, 500);
        }
    }

    /**
     * Handle service response in a unified way
     *
     * @param mixed $result Original result from service
     * @param callable|null $successCallback Callback for success, receives data parameter
     * @param int|null $errorHttpStatus HTTP status code for error, if null will use default
     * @return JsonResponse
     * @throws InvalidArgumentException
     */
    protected function handleServiceResponse($result, callable $successCallback = null, int $errorHttpStatus = 200): JsonResponse
    {
        $code = ArrayHelper::getValue($result, 'code', 0);
        $msg = ArrayHelper::getValue($result, 'msg', '');
        $extra = ArrayHelper::getValue($result, 'extra', '');
        
        if ($code === 1 || $code === 200) {
            $data = ArrayHelper::getValue($result, 'data', []);
            
            // If success callback provided, process data with it
            if ($successCallback !== null) {
                $data = $successCallback($data);
            }
            
            return JsonResponse::success($data);
        }
        
        return JsonResponse::error($code, $msg, $extra, $errorHttpStatus);
    }
}